package com.kakarote.ids.provider.common;

import cn.hutool.core.util.StrUtil;
import com.kakarote.common.entity.UserInfo;
import com.kakarote.common.redis.Redis;
import com.kakarote.common.servlet.UserStrategy;
import com.kakarote.common.utils.UserUtil;
import com.kakarote.ids.provider.utils.UserCacheUtil;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

@Aspect
@Component
public class UserAspect implements Ordered, UserStrategy {
    @Autowired
    private Redis redis;

    private static final ThreadLocal<UserInfo> USER_THREAD_LOCAL = new ThreadLocal<>();

    @PostConstruct
    public void init() {
        UserUtil.setUserStrategy(this);
    }

    @Around("execution(@(org.springframework.web.bind.annotation.*Mapping) * *(..)) && !execution(* com.kakarote.ids.provider.service..*(..)))")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        try {
            if (attributes != null) {
                UserInfo info;
                HttpServletRequest request = attributes.getRequest();
                String token = request.getHeader("AUTH-TOKEN");
                if (StrUtil.isNotEmpty(token) && this.redis.exists(token)) {
                    info = this.redis.get(token);
                } else {
                    info = (new UserInfo()).setUserId(Long.valueOf(0L));
                }
                setUser(info);
            }
            return point.proceed();
        } finally {
            removeUser();
        }
    }

    public int getOrder() {
        return 1;
    }

    public UserInfo getUser() {
        return USER_THREAD_LOCAL.get();
    }

    public void setUser(UserInfo user) {
        USER_THREAD_LOCAL.set(user);
    }

    public void setUser(Long userId) {
        UserInfo userInfo = UserCacheUtil.getUserInfo(userId);
        setUser(userInfo);
    }

    public void removeUser() {
        USER_THREAD_LOCAL.remove();
    }
}
